#pragma once

#include <fstream>
#include <unordered_map>
#include <pthread.h>
#include "Socket.hpp"
#include "Request.hpp"

const uint16_t default_port = 8080;

class HttpServer;

class ThreadData
{
public:
    ThreadData(int fd, HttpServer *sp)
        : sockfd_(fd), hsvp_(sp)
    {
    }

public:
    int sockfd_;
    HttpServer *hsvp_;
};

class HttpServer
{
public:
    HttpServer(uint16_t port = default_port)
        : port_(port)
    {
        content_type_.insert({".html", "text/html"});
        content_type_.insert({".jpg", "image/jpeg"});
        content_type_.insert({".png", "image/png"});
    }
    void Start()
    {
        listenfd_.CreateSock();
        listenfd_.Bind(port_);
        listenfd_.Listen();
        for (;;)
        {
            std::string client_ip;
            uint16_t client_port;
            int fd = listenfd_.Accept(&client_ip, &client_port);
            // 如果创建失败则重新进入循环
            if (fd < 0)
                continue;
            lg(Info, "accept a new client, %s:%d", client_ip.c_str(), client_port);
            // ThreadData td(fd, this);
            // pthread_t tid;
            // pthread_create(&tid, nullptr, Routine, (void *)&td);

            // 可以定义在堆上
            pthread_t tid;
            ThreadData *td = new ThreadData(fd, this);
            pthread_create(&tid, nullptr, Routine, td);
        }
    }

    static void *Routine(void *args)
    {
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->hsvp_->Handle(td->sockfd_);
        delete td; // 如果定义在堆上，则需记得delete
        return nullptr;
    }

    std::string ReadHtmlContent(const std::string &path)
    {
        // 使用ifstream而不是fstream，参数要加binary
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return "";
        in.seekg(0, std::ios_base::end);
        int len = in.tellg();
        in.seekg(0, std::ios_base::beg);

        std::string content;
        content.resize(len);

        in.read((char *)content.c_str(), content.size());
        in.close();
        return content;
    }

    std::string SuffixParsing(const std::string &suffix)
    {
        auto ret = content_type_.find(suffix);
        if (ret == content_type_.end())
            return content_type_[".html"];
        return content_type_[suffix];
    }

    void Handle(int sockfd)
    {
        char buff[1024];
        // 进行一次即可
        //  for (;;)
        //  {
        // path_file = "";
        // ssize_t sz = read(sockfd, buff, sizeof(buff));       //与recv效果一样
        ssize_t sz = recv(sockfd, buff, sizeof(buff) - 1, 0); // 留个位置给\0
        // 当接收到消息时才进行处理，否则不做任何操作，变量也可定义再if的作用域内
        if (sz > 0)
        {
            buff[sz] = 0;
            std::string content = buff;
            Request rq;
            rq.Deserialize(content);
            rq.Parse();
            rq.Print(); // 先解析再打印
            std::string path_file = rq.GetPathFile();
            std::string suffix = rq.GetSuffix();

            // std::string respone_line = "HTTP/1.1 200 Connection Established";
            // // std::string text = "snowdragon";
            // std::string text = ReadHtmlContent("./wwwroot/index.html");
            // std::string content_len = std::to_string(text.size());
            // std::string blank_line = "\r\n\r\n";
            // std::string respone = respone_line;
            // respone += splitting_symbol;
            // respone += content_len;
            // respone += splitting_symbol;
            // respone += blank_line;
            // respone += text;
            // write(sockfd, respone.c_str(), respone.size());

            std::string text = ReadHtmlContent(path_file);
            std::string respone_line;
            if (text.empty())
            {
                respone_line = "HTTP/1.1 404 Not Found";
                text = ReadHtmlContent(root_directory + "/error.html");
            }
            else
                respone_line = "HTTP/1.1 200 OK";
            // respone_line = "HTTP/1.1 302 Found";
            // std::string text = "snowdragon";
            // std::string content_len = std::to_string(text.size());
            std::string blank_line = "\r\n"; // 空行只需要\r\n即可，不需要多写一遍，否则打开图片时会显示不出来
            std::string respone = respone_line;
            respone += "\r\n";
            respone += "Content-Length:";
            respone += std::to_string(text.size()); // 直接写上即可，无需再定义变量存储
            respone += "\r\n";
            respone += "Content-Type:";
            respone += SuffixParsing(suffix);
            respone += "\r\n";
            // respone += "Location: https://gitee.com/snow-dragon_l";
            // respone += "\r\n";
            // respone += "Set-CooKie: name=snowdragon&&passwd=8888";
            // respone += "\r\n";
            respone += blank_line;
            respone += text;
            // write(sockfd, respone.c_str(), respone.size());
            send(sockfd, respone.c_str(), respone.size(), 0);
            // }
        }
        close(sockfd);
    }

private:
    Socket listenfd_;
    uint16_t port_;
    std::unordered_map<std::string, std::string> content_type_;
};
